#include "../pch.h"
#include "REFEncoding.h"
#include "REFBaseCodePageEncoding.h"
#include "REFSBCSCodePageEncoding.h"
#include "REFDecoderReplacementFallback.h"

#define	UNKNOWN_CHAR	(UCHAR)0xFFFD

namespace BFX
{

/////////////////////////////////////////////////////////////////////////////
// 

//
// Constructors
//
REFSBCSCodePageEncoding::REFSBCSCodePageEncoding(int nCodePage)
	: REFBaseCodePageEncoding(nCodePage, nCodePage)
{
	m_pMapBytesToUnicode = NULL;
	m_pMapUnicodeToBytes = NULL;
	m_pMapCodePageCached = NULL;

	m_byteUnknown = '?';
	m_charUnknown = '?';
}
REFSBCSCodePageEncoding::REFSBCSCodePageEncoding(int nCodePage, int nDataCodePage)
	: REFBaseCodePageEncoding(nCodePage, nDataCodePage)
{
	m_pMapBytesToUnicode = NULL;
	m_pMapUnicodeToBytes = NULL;
	m_pMapCodePageCached = NULL;

	m_byteUnknown = '?';
	m_charUnknown = '?';
}

//
// Overrides
//
int REFSBCSCodePageEncoding::GetMaxByteCount(int nCharCount) const
{
	BFX_REQUIRE (nCharCount >= 0 && "Non-negative number required.");

	// Characters would be # of characters + 1 in case high surrogate is ? * max fallback
	long long lByteCount = (long long)nCharCount + 1;

	BFX_ENSURE1 (lByteCount <= 0x7fffffff, "Too many characters. The resulting number of bytes is larger than what can be returned as an int.");
	return (int)lByteCount;
}

int REFSBCSCodePageEncoding::GetMaxCharCount(int nByteCount) const
{
	BFX_REQUIRE (nByteCount >= 0 && "Non-negative number required.");

	// Just return length, SBCS stay the same length because they don't map to surrogate
	long long lCharCount = (long long)nByteCount;

	BFX_ENSURE1 (lCharCount <= 0x7fffffff, "Too many characters. The resulting number of bytes is larger than what can be returned as an int.");

	return (int)lCharCount;
}

// GetByteCount
// Note: We start by assuming that the output will be the same as count.  Having
// an encoder or fallback may change that assumption
int REFSBCSCodePageEncoding::GetByteCount(const UCHAR* pChars, int nCount) const
{
	// Just need to BFX_ASSERT, this is called by something else internal that checked parameters already
	BFX_REQUIRE(nCount >= 0);
	BFX_REQUIRE(pChars != NULL);

	CheckMemorySection();

	// It had a funky fallback, so its more complicated
	bool bFallingBack = false;

	// prepare our end
	int nByteCount = 0;
	const UCHAR* pCharEnd = pChars + nCount;

	// Now we may have fallback char[] already from the encoder

	// Go ahead and do it, including the fallback.
	UCHAR ch;
	while ((ch = bFallingBack ? '?' : '\0') != 0 || pChars < pCharEnd)
	{
		bFallingBack = false;

		// First unwind any fallback
		if (ch == 0)
		{
			// No fallback, just get next char
			ch = *pChars;
			pChars++;
		}

		// get byte for this char
		BYTE byteTemp = m_pMapUnicodeToBytes[ch];

		// Check for fallback, this'll catch surrogate pairs too.
		if (byteTemp == 0 && ch != (UCHAR)0)
		{
			// Get Fallback
			bFallingBack = true;
			pChars ++;

			continue;
		}

		// We'll use this one
		nByteCount++;
	}

	// BFX_ASSERT(pFallbackBuffer == NULL || pFallbackBuffer->GetRemaining() == 0);	// Expected Empty fallback buffer at end

	return nByteCount;
}

int REFSBCSCodePageEncoding::GetBytes(const UCHAR* pChars, int nCharCount, OUT BYTE* pBytes, int nByteCount) const
{
	// Validate the parameters.
	BFX_REQUIRE (pChars != NULL && pBytes != NULL && "Null reference of argument disallowed.");
	BFX_REQUIRE (nCharCount >= 0 && nByteCount >= 0 && "Non-negative number required.");

	CheckMemorySection();

	// prepare our end
	BYTE* pByteStart = pBytes;
	const UCHAR* pCharStart = pChars;
	const UCHAR* pCharEnd = pChars + nCharCount;

	// TODO: fast version for replacement fallback.

	// Slower version, have to do real fallback.

	// For fallback
	bool bFallingBack = false;

	// prepare our end
	BYTE* pByteEnd = pBytes + nByteCount;

	// Now we may have fallback char[] already from the encoder fallback above

	// Go ahead and do it, including the fallback.
	UCHAR ch;
	while ((ch = bFallingBack ? '?' : '\0') != 0 || pChars < pCharEnd)
	{	
		bFallingBack = false;

		// First unwind any fallback
		if (ch == 0)
		{
			// No fallback, just get next char
			ch = *pChars;
			pChars++;
		}

		// get byte for this char
		BYTE byteTemp = m_pMapUnicodeToBytes[ch];

		// Check for fallback, this'll catch surrogate pairs too.
		if (byteTemp == 0 && ch != (UCHAR)0)
		{
			// Get Fallback

			// Make sure we have enough room.  Each fallback char will be 1 output char
			// (or recursion exception will be thrown)
			bFallingBack = true;
			pChars ++;

			continue;
		}

		// We'll use this one
		// Bounds check
		if (pBytes >= pByteEnd)
		{
			// didn't use this char, we'll throw or use buffer
			BFX_ASSERT(!bFallingBack);	// Expected to NOT be falling back

			BFX_ASSERT(pChars > pCharStart);	// Expected chars to have advanced (normal)
			pChars--;                                       // don't use last char

			BFX_ENSURE(pChars != pCharStart);	// throw ?
			break;                                              // don't throw, stop
		}

		// Go ahead and add it
		*pBytes = byteTemp;
		pBytes++;
	}

	// Expect Empty fallback buffer for SBCS
	// BFX_ASSERT(pFallbackBuffer == NULL || pFallbackBuffer->GetRemaining() == 0);

	return (int)(pBytes - pByteStart);
}

int REFSBCSCodePageEncoding::GetCharCount(const BYTE* pBytes, int nCount, REFDecoder* pDecoder) const
{
	// Validate the parameters.
	BFX_REQUIRE (pBytes != NULL && "Null pointer disallowed");
	BFX_REQUIRE (nCount >= 0 && "Non-negative number required.");

	// Just assert, we're called internally so these should be safe, checked already
	BFX_ASSERT(pBytes != NULL);
	BFX_ASSERT(nCount >= 0);

	CheckMemorySection();


	if (GetDecoderFallback()->GetMaxCharCount() == 1)
	{
		// Just return length, SBCS stay the same length because they don't map to surrogate
		// pairs and we don't have a decoder fallback.
		return nCount;
	}

	// Might need one of these later
	REF<REFDecoderFallbackBuffer> pFallbackBuffer;

	// Have to do it the hard way.
	// Assume charCount will be == count
	int nCharCount = nCount;

	// Do it our fast way
	const BYTE* pByteEnd = pBytes + nCount;

	// Quick loop
	while (pBytes < pByteEnd)
	{
		// Faster if don't use *bytes++;
		UCHAR c;
		c = m_pMapBytesToUnicode[*pBytes];
		pBytes++;

		// If unknown we have to do fallback count
		if (c == UNKNOWN_CHAR)
		{
			// Must have a fallback buffer
			if (pFallbackBuffer == NULL)
			{
				// Need to adjust count so we get real start
				if (pDecoder == NULL)
					pFallbackBuffer = GetDecoderFallback()->CreateFallbackBuffer();
				else
					pFallbackBuffer = pDecoder->GetFallbackBuffer();
				pFallbackBuffer->Initialize(pByteEnd - nCount, NULL);
			}

			// Use fallback buffer
			SequenceT<BYTE> bytesUnknown;
			bytesUnknown.Append(*(pBytes - 1));
			nCharCount--;                            // We'd already reserved one for *(bytes-1)
			nCharCount += pFallbackBuffer->Fallback(bytesUnknown, pBytes);
		}
	}

	// Fallback buffer must be empty
	BFX_ASSERT1(pFallbackBuffer == NULL || pFallbackBuffer->GetRemaining() == 0, "Expected Empty fallback buffer at end");

	// Converted sequence is same length as input
	return nCharCount;
}

int REFSBCSCodePageEncoding::GetChars(const BYTE* pBytes, int nByteCount, OUT UCHAR* pChars, int nCharCount, REFDecoder* pDecoder) const
{
	// Validate the parameters.
	BFX_REQUIRE (pChars != NULL && pBytes != NULL && "Null pointer is disallowed.");
	BFX_REQUIRE (nCharCount >= 0 && nByteCount >= 0 && "Non-negative number required.");

	CheckMemorySection();

	// Do it fast way if using ? replacement or best fit fallbacks
	const BYTE* pByteStart = pBytes;
	const BYTE* pByteEnd = pBytes + nByteCount;
	UCHAR* pCharStart = pChars;

	if (GetDecoderFallback()->GetMaxCharCount() == 1)
	{
		// Try it the fast way
		UCHAR replacementChar = ((REFDecoderReplacementFallback*)GetDecoderFallback())->GetReplacementChar();;

		// Need byteCount chars, otherwise too small buffer
		if (nCharCount < nByteCount)
		{
			// Need at least 1 output byte, throw if must throw
			BFX_REQUIRE(nCharCount >= 1);

			// Not throwing, use what we can
			pByteEnd = pBytes + nCharCount;
		}

		// Quick loop, just do '?' replacement because we don't have fallbacks for decodings.
		while (pBytes < pByteEnd)
		{
			UCHAR c = m_pMapBytesToUnicode[*pBytes];
			pBytes++;

			if (c == UNKNOWN_CHAR)
				// This is an invalid byte in the ASCII encoding.
				*pChars = replacementChar;
			else
				*pChars = c;
			pChars++;
		}

		// bytes & chars used are the same
		// TODO: if (pDecoder != NULL)
		// TODO:	pDecoder->m_nBytesUsed = (int)(pBytes - pByteStart);
		return (int)(pChars - pCharStart);
	}

	// Slower way's going to need a fallback buffer
	REF<REFDecoderFallbackBuffer> pFallbackBuffer;
	UCHAR* pCharEnd = pChars + nCharCount;

	// Not quite so fast loop
	while (pBytes < pByteEnd)
	{
		// Faster if don't use *pBytes++;
		UCHAR c = m_pMapBytesToUnicode[*pBytes];
		pBytes++;

		// See if it was unknown
		if (c == UNKNOWN_CHAR)
		{
			// Make sure we have a fallback buffer
			if (pFallbackBuffer == NULL)
			{
				if (pDecoder == NULL)
					pFallbackBuffer = GetDecoderFallback()->CreateFallbackBuffer();
				else
					pFallbackBuffer = pDecoder->GetFallbackBuffer();
				pFallbackBuffer->Initialize(pByteEnd - nByteCount, pCharEnd);
			}

			// Use fallback buffer
			BFX_ASSERT1(pBytes > pByteStart, "Expected bytes to have advanced already (unknown byte)");
			SequenceT<BYTE> bytesUnknown;
			bytesUnknown.Append(*(pBytes - 1));
			// Fallback adds fallback to chars, but doesn't increment chars unless the whole thing fits.
			if (!pFallbackBuffer->Fallback(bytesUnknown, pBytes, INOUT pChars))
			{
				// May or may not throw, but we didn't get this byte
				pBytes--;                                           // unused byte
				pFallbackBuffer->ResetAll();                        // Didn't fall this back
				BFX_ENSURE(pBytes != pByteStart);					// throw?
				break;                                              // don't throw, but stop loop
			}
		}
		else
		{
			// Make sure we have buffer space
			if (pChars >= pCharEnd)
			{
				BFX_ASSERT(pBytes > pByteStart);	// Expected bytes to have advanced already (known byte)
				pBytes--;                                           // unused byte
				BFX_ENSURE(pBytes != pByteStart);					// throw?
				break;                                              // don't throw, but stop loop
			}

			*(pChars) = c;
			pChars++;
		}
	}

	// Expect Empty fallback buffer for GetChars
	BFX_ASSERT1(pFallbackBuffer == NULL || pFallbackBuffer->GetRemaining() == 0, "Expected Empty fallback buffer at end.");

	return (int)(pChars - pCharStart);
};

// We have a managed code page entry, so load our tables
// SBCS data section looks like:
//
// char[256]  - what each byte maps to in unicode.  No support for surrogates. 0 is undefined code point
//              (except 0 for byte 0 is expected to be a real 0)
//
// byte/char* - Data for best fit (unicode->bytes), again no best fit for Unicode
//              1st WORD is Unicode // of 1st character position
//              Next bytes are best fit byte for that position.  Position is incremented after each byte
//              byte < 0x20 means skip the next n positions.  (Where n is the byte #)
//              byte == 1 means that next word is another unicode code point #
//              byte == 0 is unknown.  (doesn't override initial UCHAR[256] table!
void REFSBCSCodePageEncoding::LoadManagedCodePage()
{
	// Should be loading OUR code page
	BFX_ASSERT(m_pCodePage->CodePage == m_nDataTableCodePage);

	// Make sure we're really a 1 byte code page
	BFX_ENSURE1 (m_pCodePage->ByteCount == 1, "No data is available for current encoding.");

	// Remember our unknown bytes & chars
	m_byteUnknown = (BYTE)m_pCodePage->ByteReplace;
	m_charUnknown = m_pCodePage->UnicodeReplace;

	// Get our mapped section 65536 bytes for unicode->bytes, 256 * 2 bytes for bytes->unicode
	// Plus 4 byte to remember CP # when done loading it. (Don't want to get IA64 or anything out of alignment)
	BYTE *pMemorySection = GetSharedMemory(65536*1 + 256*2 + 4/* + m_nExtraBytes*/);

	m_pMapBytesToUnicode = (UCHAR*)pMemorySection;
	m_pMapUnicodeToBytes = (BYTE*)(pMemorySection + 256 * 2);
	m_pMapCodePageCached = (int*)(pMemorySection + 256 * 2 + 65536 * 1);

	// If its cached (& filled in) we don't have to do anything else
	if (*m_pMapCodePageCached != 0)
	{
		BFX_ASSERT(*m_pMapCodePageCached == m_nDataTableCodePage);	// out of memory???

		// If its cached (& filled in) we don't have to do anything else
		return;
	}

	// Need to read our data file and fill in our section.
	// WARNING: Multiple code pieces could do this at once (so we don't have to lock machine-wide)
	//          so be careful here.  Only stick legal values in here, don't stick temporary values.

	// Read our data file and set mapBytesToUnicode and mapUnicodeToBytes appropriately
	// First table is just all 256 mappings
	UCHAR* pTemp = (UCHAR*)&(m_pCodePage->FirstDataWord);
	for (int b = 0; b < 256; b++)
	{
		if (pTemp[b] != 0 || b == 0)
		{
			m_pMapBytesToUnicode[b] = pTemp[b];

			if (pTemp[b] != UNKNOWN_CHAR)
				m_pMapUnicodeToBytes[pTemp[b]] = (BYTE)b;
		}
		else
		{
			m_pMapBytesToUnicode[b] = UNKNOWN_CHAR;
		}
	}

	// We're done with our mapped section, set our flag so others don't have to rebuild table.
	*m_pMapCodePageCached = m_nDataTableCodePage;
}

}	//	namespace BFX
